package mdvrp;

import java.util.*;

public class Checker {
	public static boolean is_valid_sol(MDVRPCase data, Solution solution) {
		boolean flag = true;
		flag = all_id_check(data, solution);
		if (!flag) return flag;
		flag = car_capacity_check(data, solution);
		if (!flag) return flag;
		flag = customer_visited_check(data, solution);
		return flag;
	}

	private static boolean all_id_check(MDVRPCase data, Solution solution) {
		Set<Integer> set = new HashSet<Integer>();
		for (int i = 0; i < solution.solutions.size(); i++) {
			VehicleSol sol = solution.solutions.get(i);
			if (sol.depot_id <= 0 || sol.depot_id > data.t) return false;
			if (sol.vehicle_order <= 0 || sol.vehicle_order > data.m) return false;
			if (set.contains(sol.depot_id * data.m + sol.vehicle_order - 1)) return false;
			set.add(sol.depot_id * data.m + sol.vehicle_order - 1);
			for (int j = 0; j < sol.routes.size(); j++) {
				if (sol.routes.get(j) <= 0 || sol.routes.get(j) > data.n) return false;
			}
		}
		return true;
	}

	private static boolean customer_visited_check(MDVRPCase data, Solution solution) {
		int flag[] = new int[data.n];
		for (int i = 0; i < solution.solutions.size(); i++) {
			VehicleSol sol = solution.solutions.get(i);
			for (int j = 0; j < sol.routes.size(); j++) {
				flag[sol.routes.get(j) - 1] += 1;
			}
		}
		for (int i = 0; i < data.n; i++) {
			if (flag[i] != 1) return false;
		}
		return true;
	}

	private static boolean car_capacity_check(MDVRPCase data, Solution solution) {
		for (int i = 0; i < solution.solutions.size(); i++) {
			int tmp_q = 0;
			VehicleSol sol = solution.solutions.get(i);
			for (int j = 0; j < sol.routes.size(); j++) {
				tmp_q += data.customers.get(sol.routes.get(j) - 1).q;
			}
			if (tmp_q > data.q) return false;
		}
		return true;
	}
	
	public static double calc_distance(MDVRPCase data, Solution solution) {
		double ans = 0;
		for (int i = 0; i < solution.solutions.size(); i++) {
			ans += calc_single_distance(data, solution.solutions.get(i));
		}
		return ans;
	}

	private static double calc_Euclid_distance(Depot depot, Customer customer) {
		return calc_Euclid_distance(depot.x, depot.y, customer.x, customer.y);
	}
	
	public static double calc_single_distance(MDVRPCase data, VehicleSol vehicleSol) {
		if (vehicleSol.routes.size() == 0) return 0;
		double ans = 0;
		for (int i = 1; i < vehicleSol.routes.size(); i++) {
			ans += calc_Euclid_distance(data.customers.get(vehicleSol.routes.get(i) - 1), data.customers.get(vehicleSol.routes.get(i - 1) - 1));
		}
		ans += calc_Euclid_distance(data.depots.get(vehicleSol.depot_id - 1), data.customers.get(vehicleSol.routes.get(0) - 1));
		ans += calc_Euclid_distance(data.depots.get(vehicleSol.depot_id - 1), data.customers.get(vehicleSol.routes.get(vehicleSol.routes.size() - 1) - 1));
		return ans;
	}

	private static double calc_Euclid_distance(Customer customer, Customer customer2) {
		return calc_Euclid_distance(customer2.x, customer2.y, customer.x, customer.y);
	}

	private static double calc_Euclid_distance(double x, double y, double x2, double y2) {
		return Math.sqrt((x - x2) * (x - x2) + (y - y2) * (y - y2));
	}
	
	public static double calc_delta_distance(MDVRPCase data, int add_customer_id, int depot_id) {
		return calc_Euclid_distance(data.depots.get(depot_id - 1), data.customers.get(add_customer_id - 1)) * 2;
	}
	
	public static double calc_delta_distance(MDVRPCase data, int add_customer_id, int customer_id1, int customer_id2) {
		return calc_Euclid_distance(data.customers.get(add_customer_id - 1), data.customers.get(customer_id1 - 1))
				+ calc_Euclid_distance(data.customers.get(add_customer_id - 1), data.customers.get(customer_id2 - 1))
				- calc_Euclid_distance(data.customers.get(customer_id1 - 1), data.customers.get(customer_id2 - 1));
	}
	
	public static double calc_delta_distance(MDVRPCase data, int add_customer_id, int customer_id, int depot_id, int flag) {
		return calc_Euclid_distance(data.customers.get(add_customer_id - 1), data.customers.get(customer_id - 1))
				+ calc_Euclid_distance(data.depots.get(depot_id - 1), data.customers.get(add_customer_id - 1))
				- calc_Euclid_distance(data.depots.get(depot_id - 1), data.customers.get(customer_id - 1));
	}
}
